package com.simplespringmvc.mvc.core;


import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Maps;
import com.google.common.reflect.ClassPath;
import com.simplespringmvc.mvc.annotation.*;
import com.simplespringmvc.server.SimpleTomcat;
import org.apache.catalina.LifecycleException;
import org.reflections.Reflections;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Map;
import java.util.Set;

public class ScanPackageCore {

    public static void main(String[] args) throws Exception {
        Map<String, Object> map = Maps.newConcurrentMap();
        Map<String, Object> url = Maps.newConcurrentMap();
        Reflections reflections = new Reflections("com.simplespringmvc");
        Set<Class<?>> myControllers = reflections.getTypesAnnotatedWith(MyController.class);
        Set<Class<?>> myServices = reflections.getTypesAnnotatedWith(MyService.class);

        myServices.forEach(v -> {
            try {
                Class<?> aClass = Class.forName(v.getName());
                Class<?>[] interfaces = aClass.getInterfaces();
                String typeName="";
                if(interfaces!=null && interfaces.length>0){
                     typeName = interfaces[0].getTypeName();
                }else
                    typeName=aClass.getTypeName();

                map.put(typeName, aClass.getConstructor().newInstance());
            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        myControllers.forEach(v -> {
            try {
                Class<?> aClass = Class.forName(v.getName());
                Class<?>[] interfaces = aClass.getInterfaces();
                String typeName="";
                if(interfaces!=null && interfaces.length>0){
                    typeName = interfaces[0].getTypeName();
                }else
                    typeName=aClass.getTypeName();

                Object o = aClass.getConstructor().newInstance();
                map.put(typeName, o);
                Field[] allField = aClass.getDeclaredFields();
                //TODO 进行注入bean
                for (Field field : allField) {
                    MyAutowired annotation = field.getAnnotation(MyAutowired.class);
                    if (annotation != null) {
                        field.setAccessible(true);
                        Object object = map.get(field.getType().getTypeName());
                        field.set(o,object);
                    }
                }

                //TODO 进行url跟对象的映射
                Method[] methods = aClass.getMethods();
                for (Method method :
                        methods) {
                    MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
                    if( annotation!=null){
                        String value = annotation.value();
                        url.put(value,o);
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
        });

        startService(map,url);
    }

    private static void startService( Map<String, Object> map ,Map<String, Object> url) throws LifecycleException {
        SimpleTomcat.startService(new HttpServlet() {
            @Override
            protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
                //TODO  根据url去找有没有对应的路径
                String requestURI = req.getRequestURI();
                if(requestURI.contains("/")){
                    requestURI=requestURI.split("\\/")[1];
                }
                if(url.containsKey(requestURI)){
                    Object o = url.get(requestURI);

                    Method[] methods = o.getClass().getMethods();
                    for (Method method:methods){
                        MyRequestMapping annotation = method.getAnnotation(MyRequestMapping.class);
                        if(annotation !=null
                                && annotation.value().equals(requestURI)){
                            Class<?>[] parameterTypes = method.getParameterTypes();
                            Parameter[] parameters = method.getParameters();
                            Map<String, String[]> parameterMap = req.getParameterMap();
                            Object [] params=new Object[parameterTypes.length];
                            int i=0;
                            for (Class aclass:parameterTypes){
                                Parameter parameter = parameters[i];
                                MyRquestParam myrequestParam = parameter.getAnnotation(MyRquestParam.class);
                                Class<HttpServletRequest> httpServletRequestClass = HttpServletRequest.class;
                                Class<HttpServletResponse> httpServletResponse = HttpServletResponse.class;
                                if(aclass == httpServletRequestClass){
                                    params[i]=req;
                                }
                                else if(aclass == httpServletResponse){
                                    params[i]=resp;
                                }else if (myrequestParam !=null ){
                                    String myRequestParamValue = myrequestParam.value();
                                    params[i]=parameterMap.get(myRequestParamValue)[0];
                                }else {
                                    Parameter parameterItem = parameters[i];
                                    String paramName = parameterItem.getName();
                                    params[i]=parameterMap.getOrDefault(paramName,new String[]{""})[0];
                                }
                                i++;
                            }
                            try {
                                Object mv = method.invoke(o, params);
                                //TODO 在这里判断返回的数据是页面还是json  这里就不在写了
                                // 原理是判断方法上是否有@Resopnse注解如果有代表返回的是json  用json工具转换用response输出页面
                                // 否则去项目的claapath下面的static 和template 文件下去找是否有返回的对应的页面 如果没有返回404
                                // 有通过modeldanview 取到对应参数然后把页面读取成一个字符串然后通过字符串代换技术达到数据与页面的渲染 然后用response吧数据流输出
                                System.out.println("调用方法返回结果为： "+mv);
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            } catch (InvocationTargetException e) {
                                e.printStackTrace();
                            }
                        }
                    }
                }else{
                    ServletOutputStream outputStream = resp.getOutputStream();
                    outputStream.write("没有找到对应的请求 404".getBytes());
                    outputStream.flush();
                }
            }
        });
    }
}
